/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simplemetrosystem.control.Calculation;

import java.util.ArrayList;
import simplemetrosystem.control.ElementManager;
import simplemetrosystem.model.Element.MetroEdge;
import simplemetrosystem.model.Element.MetroLine;
import simplemetrosystem.model.Element.MetroStation;
import simplemetrosystem.model.charlanguage.NameMap;

/**
 *
 * @author Eric Qian
 */
public class FindByTime implements FindWay {

    public FindByTime() {
    }

    public String getName() {
        return NameMap.getInstance().getName("Time Priority");
    }

    public MetroEdge[] findWay(MetroStation stA, MetroStation stB) {
        refrash();
        SuperStation start = getStation(stA);
        SuperStation end = getStation(stB);
        split(start);
        split(end);

        //for (int i = 0; i < superStations.size(); i++) {
        ///    System.out.println(superStations.get(i).getStation().getChineseName());
        //}
        //for (int i = 0; i < superEdges.size(); i++) {
        //    System.out.println(superEdges.get(i).getStationA().getChineseName() + "-" +
        //            superEdges.get(i).getStationB().getChineseName());
        //}

        cal(start, end);

        ArrayList<MetroEdge> edges = new ArrayList<MetroEdge>();
        SuperStation current = end;
        while (current != start) {
            //System.out.println(current.getStation().getDisplayName());
            SuperEdge aEdge = current.getFatherEdge();
            if (aEdge.getStationA() == current.getStation()) {
                for (int i = 0; i < aEdge.getEdgeSize(); i++) {
                    edges.add(aEdge.getEdgeAt(i));
                }
            } else {
                for (int i = aEdge.getEdgeSize() - 1; i >= 0; i--) {
                    edges.add(aEdge.getEdgeAt(i));
                }
            }
            current = current.getFather();
        }
        MetroEdge[] oEdge = new MetroEdge[edges.size()];
        for (int i = 0; i < oEdge.length; i++) {
            oEdge[i] = edges.get(oEdge.length - 1 - i);
        }
        return oEdge;
    }

    public void cal(SuperStation start, SuperStation end) {
        start.setTime(0);
        start.setVisited(true);

        //初始化
        for (int i = 0; i < start.getEdgeSize(); i++) {
            SuperEdge aEdge = start.getEdgeAt(i);
            SuperStation nStation;
            if (aEdge.getStationA() == start.getStation()) {
                nStation = getStation(aEdge.getStationB());
            } else {
                nStation = getStation(aEdge.getStationA());
            }
            nStation.setTime(aEdge.getTime());
            nStation.setFatherEdge(aEdge);
            nStation.setFather(start);
        }

        for (int i = 1; i < superStations.size(); i++) {
            double min = 99999;
            SuperStation minStation = null;
            for (int j = 0; j < superStations.size(); j++) {
                if (superStations.get(j).getTime() < min &&
                        !superStations.get(j).isVisited()) {
                    minStation = superStations.get(j);
                    min = minStation.getTime();

                }
            }

            minStation.setVisited(true);

            for (int k = 0; k < minStation.getEdgeSize(); k++) {
                SuperEdge aEdge = minStation.getEdgeAt(k);
                SuperStation nStation;
                if (aEdge.getStationA() == minStation.getStation()) {
                    nStation = getStation(aEdge.getStationB());
                } else {
                    nStation = getStation(aEdge.getStationA());
                }
                if (nStation.isVisited() == false) {
                    double tTim = 0;
                    if (nStation.getTime() > 50000) {
                        tTim = minStation.getTime() + aEdge.getTime();
                    } else {
                        tTim = minStation.getTime() + nStation.getTime() + aEdge.getTime();
                    }
                    if (tTim < nStation.getTime()) {
                        nStation.setTime(tTim);
                        nStation.setFather(minStation);
                        nStation.setFatherEdge(aEdge);
                    }
                }
            }
            // System.out.println(i + " minStation " + minStation.getStation().getDisplayName());
            //for (int s = 0; s < superStations.size(); s++) {
            //    System.out.println(superStations.get(s).getStation().getChineseName() +
            //            superStations.get(s).getTime());
            //   if (superStations.get(s).getFather() != null) {
            //      System.out.println(superStations.get(s).getStation().getChineseName() + " father: " +
            //              superStations.get(s).getFather().getStation().getChineseName());
            // }
            //}
            //System.out.println();
        }
    }

    private void refrash() {
        superStations = new ArrayList<SuperStation>();
        superEdges =
                new ArrayList<SuperEdge>();
        ElementManager elementManager = ElementManager.getInstance();
        MetroEdge[] mEdges;

        for (int i = 0; i <
                elementManager.getLinesSize(); i++) {
            MetroLine aLine = elementManager.getLineAt(i);
            if (aLine.getStatus().equals(MetroLine.STATUS_METRO)) {
                int start = 0;
                for (int j = 0; j <
                        aLine.getEdgesSize(); j++) {
                    MetroEdge aEdge = aLine.getEdgeAt(j);
                    //System.out.println("!" + aEdge.getStationB().getDisplayName());
                    if (aEdge.getStationB().getLinesSize() > 1 ||
                            aEdge.getStationB().getEdgesSize() != 2) {
                        mEdges = new MetroEdge[j - start + 1];
                        for (int k = start; start <
                                j + 1; start++) {
                            mEdges[start - k] = aLine.getEdgeAt(start);
                        }

                        SuperEdge nEdge = new SuperEdge(mEdges);
                        superEdges.add(nEdge);
                        getStation(nEdge.getStationA()).addEdge(nEdge);
                        getStation(nEdge.getStationB()).addEdge(nEdge);
                    }

                }
            } else {
                for (int j = 0; j <
                        aLine.getEdgesSize(); j++) {
                    MetroEdge aEdge = aLine.getEdgeAt(j);
                    mEdges =
                            new MetroEdge[1];
                    mEdges[0] = aEdge;
                    SuperEdge nEdge = new SuperEdge(mEdges);
                    superEdges.add(nEdge);
                    getStation(nEdge.getStationA()).addEdge(nEdge);
                    getStation(nEdge.getStationB()).addEdge(nEdge);
                }

            }
        }
    }

    private void split(SuperStation station) {
        if (station.getEdgeSize() == 0) {
            for (int i = 0; i <
                    superEdges.size(); i++) {
                int loc = superEdges.get(i).containStation(station.getStation());
                if (loc > 0) {
                    SuperEdge rEdge = superEdges.get(i);
                    SuperEdge edgeA = new SuperEdge(rEdge.getSubEdges(loc, true));
                    SuperEdge edgeB = new SuperEdge(rEdge.getSubEdges(loc, false));
                    SuperStation stA = getStation(rEdge.getStationA());
                    SuperStation stB = getStation(rEdge.getStationB());

                    stA.removeEdge(rEdge);
                    stA.addEdge(edgeA);
                    stB.removeEdge(rEdge);
                    stB.addEdge(edgeB);
                    station.addEdge(edgeA);
                    station.addEdge(edgeB);

                    superEdges.remove(rEdge);
                    superEdges.add(edgeA);
                    superEdges.add(edgeB);
                }

            }
        }
    }

    /**
     * 
     * @param station
     * @return
     */
    private SuperStation getStation(MetroStation station) {
        for (int i = 0; i <
                superStations.size(); i++) {
            if (superStations.get(i).getStation() == station) {
                return superStations.get(i);
            }

        }
        SuperStation aStation = new SuperStation(station);
        superStations.add(aStation);
        return aStation;
    }
    private ArrayList<SuperEdge> superEdges;
    private ArrayList<SuperStation> superStations;
}
